﻿using Microsoft.Extensions.DependencyInjection;
using WH.Model.OrgContext;
using Rw.Core.Common;
using WH.Common.Attributes;
using WH.Common.Bases.IBase;
using WH.Common.Cache;
using WH.Common.Config;
using WH.Common.UniOfWork;
using SqlSugar;
using System.Reflection;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Collections.Generic;
using Rw.Core.Common.Helper;

namespace WH.Extensions.Setup
{
    public static class SqlSugarSetupWithConfigSetup
    {

        private const string secret = "rw_mysql_aes_2022";

        private static bool IsAutoCloseConnection = true;
        /// <summary>
        /// 注入sqlsugar（启用缓存）
        /// </summary>
        /// <param name="services"></param>
        /// <param name="config"></param>
        public static void AddSqlSugarSetupWithConfigSetup(this IServiceCollection services)
        {
            var expMethods = new List<SqlFuncExternal>();
            expMethods.Add(new SqlFuncExternal()
            {
                UniqueMethodName = "AesEncrypt",
                MethodValue = (expInfo, dbType, expContext) =>
                {
                    if (dbType == DbType.MySql)
                        return $"HEX( AES_ENCRYPT({expInfo.Args[0].MemberName},'{secret}'))";
                    else
                        throw new Exception("未实现");
                }
            });
            expMethods.Add(new SqlFuncExternal()
            {
                UniqueMethodName = "AesDecrypt",
                MethodValue = (expInfo, dbType, expContext) =>
                {
                    if (dbType == DbType.MySql)
                        return $"AES_DECRYPT( UNHEX({expInfo.Args[0].MemberName}),'{secret}' )";
                    else
                        throw new Exception("未实现");
                }
            });

            var provider = services.BuildServiceProvider().CreateScope();

            var caching = provider.ServiceProvider.GetRequiredService<ICaching>();
            var configurationCenter = provider.ServiceProvider.GetRequiredService<IConfigurationCenter>();

            DbType dbType = DbType.Sqlite;
            string connectionString = $"datasource={Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "rw_ap_db.db")}"; //$"datasource={Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "rw_ap_db.db")}";//Data Source=:memory:

            //var config = new DatabaseConfigurationProvider();

            var connStr = configurationCenter.ConnectionString;
            var dt = configurationCenter.DbType;

            if (!string.IsNullOrWhiteSpace(connStr) && !string.IsNullOrWhiteSpace(dt))
            {
                var dtype = (DbType)int.Parse(dt);

                if (IsConnectionStringValid(connStr, dtype))
                {
                    dbType = dtype;
                    connectionString = connStr;
                    IsAutoCloseConnection = true;
                }
            }

            services.AddScoped<ISqlSugarClient>((s) =>
            {
                var sugarClient = new SqlSugarClient(new ConnectionConfig
                {
                    ConnectionString = connectionString,
                    DbType = dbType,
                    IsAutoCloseConnection = IsAutoCloseConnection,
                    ConfigureExternalServices = new ConfigureExternalServices()
                    {
                        DataInfoCacheService = caching,
                        SqlFuncServices = expMethods,//set ext method
                        EntityNameService = (type, entity) =>
                        {
                            entity.IsDisabledDelete = true;
                        }
                    },
                    MoreSettings = new ConnMoreSettings()
                    {
                        IsWithNoLockQuery = true,
                        IsAutoRemoveDataCache = true,
                        SqliteCodeFirstEnableDefaultValue = true //启用默认值
                    },
                    AopEvents = new AopEvents()
                    {
                        //患者姓名加密解密处理
                        DataExecuting = (oldValue, entityInfo) =>
                        {
                            //if ((entityInfo.OperationType == DataFilterType.InsertByObject))
                            //{
                            //    if (entityInfo.PropertyName == nameof(IOrganization.OrganizationId))
                            //    {
                            //        if (oldValue as string == BusinessFunction.TopOrganiztionParentId)
                            //        {
                            //            throw new BadRequestException("管理员机构不允许添加数据");
                            //        }
                            //    }
                            //}

                            //if (entityInfo.OperationType == DataFilterType.InsertByObject)
                            //{
                            //    if (entityInfo.PropertyName == nameof(IAuditable.CreatedTime))
                            //    {
                            //        entityInfo.SetValue(DateTime.Now);
                            //    }

                            //    if (entityInfo.PropertyName == nameof(IAuditable.CreatedBy))
                            //    {
                            //        var provider = services.BuildServiceProvider().CreateScope();
                            //        var context = provider.ServiceProvider.GetRequiredService<OrganizationContext>();
                            //        entityInfo.SetValue(context?.UserId ?? "");
                            //    }
                            //}

                            //if (entityInfo.OperationType == DataFilterType.UpdateByObject)
                            //{
                            //    if (entityInfo.PropertyName == nameof(IAuditable.UpdatedTime))
                            //    {
                            //        entityInfo.SetValue(DateTime.Now);
                            //    }

                            //    if (entityInfo.PropertyName == nameof(IAuditable.UpdatedBy))
                            //    {
                            //        var provider = services.BuildServiceProvider().CreateScope();
                            //        var context = provider.ServiceProvider.GetRequiredService<OrganizationContext>();
                            //        entityInfo.SetValue(context?.UserId ?? "");
                            //    }
                            //}

                            if (entityInfo.OperationType == DataFilterType.InsertByObject || entityInfo.OperationType == DataFilterType.UpdateByObject)
                            {
                                var encryptFieldAttribute = entityInfo.GetAttribute<EncryptFieldAttribute>();

                                if (encryptFieldAttribute is not null && encryptFieldAttribute.IsEncrypt == true)
                                {
                                    entityInfo.SetValue(MysqlAesHelper.Encrypt(oldValue as string ?? string.Empty));
                                }
                            }

                            /*** 列级别事件：插入的每个列都会进事件 ***/

                            if (entityInfo.OperationType == DataFilterType.InsertByObject || entityInfo.OperationType == DataFilterType.UpdateByObject)
                            {
                                var encryptFieldAttribute = entityInfo.GetAttribute<EncryptFieldAttribute>();

                                if (encryptFieldAttribute is not null && encryptFieldAttribute.IsEncrypt == true)
                                {
                                    entityInfo.SetValue(MysqlAesHelper.Encrypt(oldValue as string ?? string.Empty));
                                }
                            }

                            //清空UnionALL缓存
                            if (entityInfo.OperationType == DataFilterType.InsertByObject || entityInfo.OperationType == DataFilterType.UpdateByObject || entityInfo.OperationType == DataFilterType.DeleteByObject)
                            { /*** 行级别事件 ：更新一条记录只进一次 ***/
                                if (entityInfo.EntityColumnInfo.IsPrimarykey)
                                {
                                    Task.Run(() =>
                                    {
                                        //entityInfo.EntityColumnInfo.PropertyInfo.get;
                                        var removeCacheAttribute = entityInfo.EntityValue.GetType().GetCustomAttribute<RemoveCacheAttribute>();

                                        if (removeCacheAttribute is not null && removeCacheAttribute.Enable == true)
                                        {
                                            if (removeCacheAttribute.RemoveKeys is not null && removeCacheAttribute.RemoveKeys.Length > 0)
                                            {
                                                foreach (var key in removeCacheAttribute.RemoveKeys)
                                                {
                                                    var cacheKeys = caching.GetAllKey(key);

                                                    foreach (var cacheKey in cacheKeys)
                                                    {
                                                        caching.Remove(cacheKey);
                                                    }
                                                }

                                            }
                                        }
                                    });
                                    //entityInfo.EntityValue 拿到单条实体对象
                                }
                            }
                        },

                        DataExecuted = (value, entity) =>
                        {
                            //只有行级事件

                            foreach (var item in entity.EntityColumnInfos)
                            {
                                var attr = item.PropertyInfo.GetCustomAttribute<EncryptFieldAttribute>();

                                if (attr is not null && attr.IsEncrypt == true)
                                {
                                    var newValue = entity.GetValue(item.PropertyName);
                                    entity.SetValue(item.PropertyName, MysqlAesHelper.Decrypt(newValue as string ?? string.Empty));
                                }
                            }

                        },

                        OnLogExecuting = (sql, pars) =>
                        {
                            //Console.WriteLine(sql);
                        }
                    },
                }, db =>
                {
                    //OrganizationContext context = new OrganizationContext(db);

                    //db.QueryFilter.AddTableFilterIF<IOrganizationFilter>(context.OrganizationIds is not null, x => context.OrganizationIds.Contains(x.OrganizationId));
                    db.QueryFilter.AddTableFilter<ISoftFilter>(x => x.IsDelete == false);
                });

                return sugarClient;
            });

            services.AddScoped<IUnitOfWork, UnitOfWork>();

            services.AddScoped<OrganizationContext>();

        }


        public static bool IsConnectionStringValid(string connectionString, DbType dbType)
        {
            var db = new SqlSugarClient(new ConnectionConfig
            {
                ConnectionString = connectionString,
                DbType = dbType,
                IsAutoCloseConnection = true,
                InitKeyType = InitKeyType.Attribute
            });

            try
            {
                var isValid = db.Ado.IsValidConnection();
                return isValid;
            }
            catch
            {
                return false;
            }
        }
    }
}
